package com.zhuo.project.order.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import com.zhuo.common.enums.IsEquipStatus;
import com.zhuo.common.enums.IsSendStatus;
import com.zhuo.common.enums.SendStatus;
import com.zhuo.common.utils.DateUtils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.zhuo.common.utils.IdUtils;
import com.zhuo.common.utils.SecurityUtils;
import com.zhuo.framework.redis.RedisCache;
import com.zhuo.project.order.domain.ZzDiagnoseDetail;
import com.zhuo.project.order.domain.ZzDiagnoseHead;
import com.zhuo.project.order.domain.ZzDiagnoseSend;
import com.zhuo.project.order.domain.ZzTask;
import com.zhuo.project.order.dto.k3.AccessResult;
import com.zhuo.project.order.dto.k3.ReturnInfo;
import com.zhuo.project.order.dto.k3.ReturnInfoDto;
import com.zhuo.project.order.dto.k3.ReturnJsonDto;
import com.zhuo.project.order.dto.k3.ReturnK3Dto;
import com.zhuo.project.order.mapper.ZzDiagnoseReturnMapper;
import com.zhuo.project.order.domain.ZzDiagnoseReturn;
import com.zhuo.project.order.service.IZzDiagnoseDetailService;
import com.zhuo.project.order.service.IZzDiagnoseHeadService;
import com.zhuo.project.order.service.IZzDiagnoseReturnService;
import com.zhuo.project.order.service.IZzDiagnoseSendService;
import com.zhuo.project.order.service.IZzTaskService;
import com.zhuo.project.order.service.task.K3Service;

import cn.hutool.json.JSONUtil;

/**
 * 处方单退药明细Service业务层处理
 *
 * @author zhuo
 * @date 2020-03-26
 */
@Service
public class ZzDiagnoseReturnServiceImpl implements IZzDiagnoseReturnService {

    private static Logger logger = LoggerFactory.getLogger(ZzDiagnoseReturnServiceImpl.class);
    @Autowired
    private ZzDiagnoseReturnMapper zzDiagnoseReturnMapper;

    @Autowired
    private IZzTaskService iZzTaskService;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private IZzDiagnoseSendService iZzDiagnoseSendService;

    @Autowired
    private IZzDiagnoseDetailService iZzDiagnoseDetailService;

    @Autowired
    private K3Service k3Service;

    @Autowired
    private IZzDiagnoseHeadService iZzDiagnoseHeadService;

    /**
     * 查询处方单退药明细
     *
     * @param id 处方单退药明细ID
     * @return 处方单退药明细
     */
    @Override
    public ZzDiagnoseReturn selectZzDiagnoseReturnById(Long id) {
        return zzDiagnoseReturnMapper.selectZzDiagnoseReturnById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void sendReturnOrder2K3(ZzTask zzTask) throws Exception{
        String returnId = zzTask.getRefId();

        ZzDiagnoseReturn zzDiagnoseReturnSearch =  new ZzDiagnoseReturn();
        zzDiagnoseReturnSearch.setReturnId(returnId);
        List<ZzDiagnoseReturn> list = zzDiagnoseReturnMapper.selectZzDiagnoseReturnList(zzDiagnoseReturnSearch);
        String token = k3Service.signIn();
        boolean isOk = false;
        String message = "";

        List<ReturnInfoDto> reqList = new ArrayList<>();
        List<ReturnJsonDto> jsonList = new ArrayList<>();

        for (ZzDiagnoseReturn zzDiagnoseReturn:list) {
            ReturnInfo returnInfo = new ReturnInfo();
            returnInfo.setACCESSTOKEN(token);
            returnInfo.setF_UN_Text8(zzDiagnoseReturn.getSendId());
            returnInfo.setF_UN_Text9(zzDiagnoseReturn.getSendItemNo().toString());
            Double fqty = zzDiagnoseReturn.getReturnQty() *1.0 * zzDiagnoseReturn.getReturnUnit();
            returnInfo.setFQty(fqty.toString());
            AccessResult accessResult = k3Service.pushMisDeliveryT(returnInfo);
            message = message + ";" + accessResult.getMessage();

            ReturnInfoDto returnInfoDto = new  ReturnInfoDto();
            returnInfoDto.setACCESSTOKEN(token);
            returnInfoDto.setF_UN_Text8(zzDiagnoseReturn.getSendId());
            returnInfoDto.setF_UN_Text9(zzDiagnoseReturn.getSendItemNo().toString());
            returnInfoDto.setFQty(fqty.toString());
            returnInfoDto.setMessage(accessResult.getMessage());
            returnInfoDto.setACCESSTOKEN(accessResult.getAccessToken());
            returnInfoDto.setCode(accessResult.getCode());
            reqList.add(returnInfoDto);
            ReturnJsonDto returnJsonDto = new ReturnJsonDto();
            returnJsonDto.setReqJson(JSONUtil.toJsonPrettyStr(returnInfo));
            returnJsonDto.setResJson(JSONUtil.toJsonPrettyStr(accessResult));
            jsonList.add(returnJsonDto);


            if(accessResult.getCode().equals("0")){
                isOk = true;
            }else {
                isOk = false;
                logger.error("推送k3退药数据错误： 退药单号=" + zzDiagnoseReturn.getReturnId());
                break;
            }
        }
        if(isOk){
            zzTask.setStatus(2);
            zzTask.setUpdateTime(new Date());
            zzTask.setRemark(message);
            iZzTaskService.updateZzTask(zzTask);
            for (ZzDiagnoseReturn zzDiagnoseReturn:list) {
                ZzDiagnoseReturn updateReturn = new ZzDiagnoseReturn();
                updateReturn.setId(zzDiagnoseReturn.getId());
                updateReturn.setSendStatus(3);
                updateReturn.setUpdateTime(new Date());
                zzDiagnoseReturnMapper.updateZzDiagnoseReturn(updateReturn);
            }
        }else {
            // 处理失败
            zzTask.setStatus(3);
            zzTask.setUpdateTime(new Date());
            zzTask.setRemark(message);
            iZzTaskService.updateZzTask(zzTask);
        }


        ReturnK3Dto returnK3Dto = new ReturnK3Dto();
        returnK3Dto.setType(zzTask.getType());
        returnK3Dto.setTypeName("退药/商品");
        returnK3Dto.setReqList(reqList);
        returnK3Dto.setJsonList(jsonList);
        redisCache.setCacheObject("zhuozheng:k3:return:"+zzTask.getRefId(), JSONUtil.toJsonStr(returnK3Dto));
    }

    /**
     * 查询处方单退药明细列表
     *
     * @param zzDiagnoseReturn 处方单退药明细
     * @return 处方单退药明细
     */
    @Override
    public List<ZzDiagnoseReturn> selectZzDiagnoseReturnList(ZzDiagnoseReturn zzDiagnoseReturn) {
        return zzDiagnoseReturnMapper.selectZzDiagnoseReturnList(zzDiagnoseReturn);
    }

    /**
     * 新增处方单退药明细
     *
     * @param zzDiagnoseReturn 处方单退药明细
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertZzDiagnoseReturn(ZzDiagnoseReturn zzDiagnoseReturn) {
        zzDiagnoseReturn.setCreateTime(DateUtils.getNowDate());
        return zzDiagnoseReturnMapper.insertZzDiagnoseReturn(zzDiagnoseReturn);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int batchInsertZzDiagnoseReturnList(Map<String, List<ZzDiagnoseReturn>> diagnoseReturnMap) throws Exception{
        // 得按照send
        int totalSize = 0;
        Iterator<Entry<String, List<ZzDiagnoseReturn>>> entries = diagnoseReturnMap.entrySet().iterator();
        String diagnoseId = "";
        while (entries.hasNext()) {
            Entry<String, List<ZzDiagnoseReturn>> entry = entries.next();
            String sendId = entry.getKey();
            List<ZzDiagnoseReturn> zzDiagnoseReturnList = entry.getValue();
            String returnId = IdUtils.simpleUUID();
            int itemNo = 0;
            totalSize = totalSize + zzDiagnoseReturnList.size();
            for (ZzDiagnoseReturn zzDiagnoseReturn : zzDiagnoseReturnList) {
                diagnoseId = zzDiagnoseReturn.getDiagnoseId();
                itemNo = itemNo + 10;
                zzDiagnoseReturn.setItemNo(itemNo);
                zzDiagnoseReturn.setReturnId(returnId);
                zzDiagnoseReturnMapper.insertZzDiagnoseReturn(zzDiagnoseReturn);
                // 更新退药数量
                ZzDiagnoseSend zzDiagnoseSend = iZzDiagnoseSendService
                        .selectZzDiagnoseSendByItemNo(zzDiagnoseReturn.getSendId(), zzDiagnoseReturn.getSendItemNo(),
                                zzDiagnoseReturn.getMaterialId());
                ZzDiagnoseSend updateSend = new ZzDiagnoseSend();
                updateSend.setId(zzDiagnoseSend.getId());
                double totalReturnQty = zzDiagnoseSend.getTotalReturnQty() + zzDiagnoseReturn.getReturnQty();
                if(totalReturnQty > zzDiagnoseSend.getSendQty()){
                    logger.error("发药单号: {}, 商品id{} 多退",zzDiagnoseReturn.getSendId(),zzDiagnoseReturn.getMaterialId());
                    throw  new Exception("系统异常：发药单号: "+ zzDiagnoseReturn.getSendId() +" 商品id多退:"+ zzDiagnoseReturn.getMaterialId());
                }
                updateSend.setTotalReturnQty(totalReturnQty);
                updateSend.setUpdateBy(SecurityUtils.getUsername());
                updateSend.setUpdateTime(new Date());
                iZzDiagnoseSendService.updateZzDiagnoseSend(updateSend);

                // 更新处方单的详情的已发数量
                List<ZzDiagnoseDetail> detailList = iZzDiagnoseDetailService.selectZzDiagnoseDetailListByOrderMaterialId(zzDiagnoseSend.getDiagnoseId(),
                        zzDiagnoseSend.getMaterialId());
                double returnQty = zzDiagnoseReturn.getReturnQty();
                for (ZzDiagnoseDetail zzDiagnoseDetail : detailList) {
                    if(zzDiagnoseDetail.getTotalSendQty()>0){
                        ZzDiagnoseDetail updateDetail = new ZzDiagnoseDetail();
                        updateDetail.setId(zzDiagnoseDetail.getId());
                        double totalSendQty = zzDiagnoseDetail.getTotalSendQty();
                        if(totalSendQty >= returnQty){
                            // 则一次性退完商品行项目
                            updateDetail.setTotalSendQty(totalSendQty - returnQty);
                            returnQty = 0.0;
                            iZzDiagnoseDetailService.updateZzDiagnoseDetail(updateDetail);
                            break;
                        }else {
                            //  分多次退
                            updateDetail.setTotalSendQty(0.0);
                            returnQty = returnQty - totalReturnQty;
                            iZzDiagnoseDetailService.updateZzDiagnoseDetail(updateDetail);
                        }

                    }
                }
                if(returnQty >0){
                    logger.error("发药单号: {}, 商品id{} 多退",zzDiagnoseReturn.getSendId(),zzDiagnoseReturn.getMaterialId());
                    throw  new Exception("系统异常：发药单号: "+ zzDiagnoseReturn.getSendId() +" 商品id多退:"+ zzDiagnoseReturn.getMaterialId());
                }

            }

            // 退药后更新处方状态，为部分发药或者全部退药

            ZzDiagnoseHead zzDiagnoseHead =
                    iZzDiagnoseHeadService.selectZzDiagnoseHeadByDiagnoseId(diagnoseId);
            Long id = zzDiagnoseHead.getId();
            ZzDiagnoseHead updateDiagnoseHead = new ZzDiagnoseHead();
            updateDiagnoseHead.setId(id);
            updateDiagnoseHead.setIsEquip(getEquipStatus(diagnoseId));
            updateDiagnoseHead.setIsSend(getSendStatus(diagnoseId));
            iZzDiagnoseHeadService.updateZzDiagnoseHead(updateDiagnoseHead);
            // 后续再优化为批量更新
            ZzTask zzTask = new ZzTask();
            zzTask.setType(50);
            zzTask.setRefId(returnId);
            zzTask.setStatus(0);
            zzTask.setContent(zzDiagnoseHead.getEncounterId());
            zzTask.setValid(1);
            zzTask.setExecCount(0);
            zzTask.setRemark("");
            zzTask.setCreateTime(new Date());
            iZzTaskService.insertZzTask(zzTask);
        }
        return totalSize;
    }

    public int getEquipStatus(String diagnoseId){
        ZzDiagnoseDetail zzDiagnoseDetailSearch = new ZzDiagnoseDetail();
        zzDiagnoseDetailSearch.setDiagnoseId(diagnoseId);
        List<ZzDiagnoseDetail> list = iZzDiagnoseDetailService.selectZzDiagnoseDetailList(zzDiagnoseDetailSearch);
        Double totalQty = list.stream().mapToDouble(ZzDiagnoseDetail::getQty).sum();
        Double totalSendQty = list.stream().mapToDouble(ZzDiagnoseDetail::getTotalSendQty).sum();

        ZzDiagnoseSend zzDiagnoseSend = new ZzDiagnoseSend();
        zzDiagnoseSend.setDiagnoseId(diagnoseId);
        zzDiagnoseSend.setSendStatus(SendStatus.EQUIP.getCode());

        List<ZzDiagnoseSend> zzDiagnoseSendList = iZzDiagnoseSendService.selectZzDiagnoseSendList(zzDiagnoseSend);
        Double totalEquitQty = zzDiagnoseSendList.stream().mapToDouble(ZzDiagnoseSend::getSendQty).sum();

        double isleft = totalQty - totalSendQty -totalEquitQty;
        if(totalSendQty + totalEquitQty == 0 ){
            return IsEquipStatus.EQUIP_NO.getCode();
        }
        if(isleft > 0){
            return IsEquipStatus.EQUIP_PART.getCode();
        }else if(isleft < 0){
            return IsEquipStatus.EQUIP_OVER.getCode();
        }else {
            return IsEquipStatus.EQUIP_DONE.getCode();
        }
    }


    public int getSendStatus(String diagnoseId){
        ZzDiagnoseDetail zzDiagnoseDetailSearch = new ZzDiagnoseDetail();
        zzDiagnoseDetailSearch.setDiagnoseId(diagnoseId);
        List<ZzDiagnoseDetail> list = iZzDiagnoseDetailService.selectZzDiagnoseDetailList(zzDiagnoseDetailSearch);
        Double totalQty = list.stream().mapToDouble(ZzDiagnoseDetail::getQty).sum();
        Double totalSendQty = list.stream().mapToDouble(ZzDiagnoseDetail::getTotalSendQty).sum();
        if(totalSendQty ==0 ){
            return IsSendStatus.SEND_NO.getCode();
        }
        if(totalQty.compareTo(totalSendQty) > 0){
            return IsSendStatus.SEND_PART.getCode();
        }else if(totalQty.compareTo(totalSendQty)==0){
            return IsSendStatus.SEND_DONE.getCode();
        }else {
            return IsSendStatus.SEND_OVER.getCode();
        }
    }

    /**
     * 修改处方单退药明细
     *
     * @param zzDiagnoseReturn 处方单退药明细
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateZzDiagnoseReturn(ZzDiagnoseReturn zzDiagnoseReturn) {
        zzDiagnoseReturn.setUpdateTime(DateUtils.getNowDate());
        return zzDiagnoseReturnMapper.updateZzDiagnoseReturn(zzDiagnoseReturn);
    }

    /**
     * 批量删除处方单退药明细
     *
     * @param ids 需要删除的处方单退药明细ID
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteZzDiagnoseReturnByIds(Long[] ids) {
        return zzDiagnoseReturnMapper.deleteZzDiagnoseReturnByIds(ids);
    }

    /**
     * 删除处方单退药明细信息
     *
     * @param id 处方单退药明细ID
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteZzDiagnoseReturnById(Long id) {
        return zzDiagnoseReturnMapper.deleteZzDiagnoseReturnById(id);
    }
}
